﻿using HlELock.Core;
using Syncfusion.Windows.Shared.Resources;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media.Animation;
using System.Xml.Serialization;

namespace HlELock
{
    public static class UsbHidExtensions
    {

        /// <summary>
        /// 向线写入时间
        /// </summary>
        public static bool LineWriteDate(this IUsbHid usbHid, DateTime dateTime)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0E50580221{dateTime.ToString("yyMMddHHmmss")}";
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToHexString();
            return cmd == result;
        }

        /// <summary>
        /// 获取线时间
        /// </summary>
        public static DateTime LineGetDate(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0750580422";
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToHexString();
            result = result.Replace(cmd, "");
            var year = int.Parse(result.Substring(0, 4));
            var month = int.Parse(result.Substring(4, 2));
            var day = int.Parse(result.Substring(6, 2));
            var hour = int.Parse(result.Substring(8, 2));
            var minute = int.Parse(result.Substring(10, 2));
            var second = int.Parse(result.Substring(12, 2));
            return new DateTime(year, month, day, hour, minute, second);
        }

        /// <summary>
        /// 向线写入有效
        /// </summary>
        public static bool LineWriteOk(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0750580219";
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToHexString();
            return cmd == result;
        }

        /// <summary>
        /// 向线写入有效
        /// </summary>
        public static bool LineWriteNo(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0750580220";
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToHexString();
            return cmd == result;
        }


        /// <summary>
        /// 向线写入编号
        /// </summary>
        public static bool LineWriteNumber(this IUsbHid usbHid, string number)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0F50580223" + number;
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToString();
            return result == "584B0F50580223";
        }

        /// <summary>
        /// 向线读取编号
        /// </summary>
        public static string LineGetNumber(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var cmd = $"584B0750580424";
            var data = usbHid.SendMessage(cmd, true);
            var result = data.ToString();
            return result.Replace(cmd, "");
        }

        /// <summary>
        /// 获取经销商编码
        /// </summary>
        public static void GetAgenyCode(this IUsbHid usbHid, Action<string> action)
        {
            usbHid.ClearEvents();
            var data = usbHid.SendMessage("584B07504B0402", true);
            var str = data.ToHexString();
            str = str.Substring(14, 4);
            action?.Invoke(str);
        }

        /// <summary>
        /// 获取酒店经销商编码
        /// </summary>
        public static void GetHotelAgenyCode(this IUsbHid usbHid, Action<string> action)
        {
            usbHid.ClearEvents();
            var data = usbHid.SendMessage("584B0750520402", true);
            var str = data.ToHexString();
            str = str.Substring(str.Length - 4, 4);
            action?.Invoke(str);
        }


        /// <summary>
        /// 获取经销商编码
        /// </summary>
        public static void GetHotelCode(this IUsbHid usbHid, Action<string> action)
        {
            usbHid.ClearEvents();
            usbHid.OnReceiveMessaged += datas =>
            {
                var str = datas.ToHexString();
                str = str.Substring(str.Length - 4, 4);
                action?.Invoke(str);
            };
            var data = usbHid.SendMessage("584B0750520404", false);
        }

        private static void UsbHid_OnReceiveMessaged(byte[] obj)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 激活酒店发卡机
        /// </summary>
        public static void ActiveHotelDevice(this IUsbHid usbHid, string areaCode, string agencyCode, string hotelCode)
        {
            usbHid.ClearEvents();
            //地区
            usbHid.SendMessage("584B0B50520201" + areaCode, true);
            Thread.Sleep(200);
            //经销商
            usbHid.SendMessage("584B0950520202" + agencyCode, true);
            Thread.Sleep(200);
            //酒店代码
            usbHid.SendMessage("584B0950520204" + hotelCode, true);
            Thread.Sleep(200);

        }

        /// <summary>
        /// 激活加密机
        /// </summary>
        /// <param name="areaCode">地区代码</param>
        /// <param name="agencyCode">经销商编码</param>
        public static void ActiveDevice(this IUsbHid usbHid, string areaCode, string agencyCode)
        {
            usbHid.ClearEvents();
            usbHid.SendMessage("584B0B504B0201" + areaCode);
            Thread.Sleep(1000);
            usbHid.SendMessage("584B09504B0202" + agencyCode);
        }


        private static int CalcQty(byte[] data)
        {
            var d = data.Take(2).ToArray().ToHexString();
            var count = string.IsNullOrWhiteSpace(d) ? 0 : Convert.ToInt32(Convert.ToInt32(d, 16));
            d = data.Skip(2).Take(2).ToArray().ToHexString();
            var qty = string.IsNullOrWhiteSpace(d) ? 0 : Convert.ToInt32(Convert.ToInt32(d, 16));
            return count - qty;
        }

        /// <summary>
        /// 获取加密卡机可刷卡次数
        /// </summary>
        /// <returns></returns>
        public static int GetNumber(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var data = usbHid.SendMessage("584B07504B0418", true);
            return CalcQty(data.Skip(7).Take(4).ToArray());
        }
        public class SendCardResult
        {
            /// <summary>
            /// 刷卡结果
            /// </summary>
            public SendCardResultType Result { get; set; }

            /// <summary>
            /// 返回的指令
            /// </summary>
            public string Order { get; set; }

            public List<string> OrderList { get; set; } = new List<string>();

            /// <summary>
            /// 剩余刷卡次数
            /// </summary>
            public int Count { get; set; }

            /// <summary>
            /// 卡号
            /// </summary>
            public string CardCode { get; set; }

            public bool IsSuccess => Result == SendCardResultType.成功;

        }
        public enum SendCardResultType
        {
            成功,
            无卡或坏卡,
            已加密卡,
            指令结束,
            等待结果
        }

        private static SendCardResult GetSendCardResult(byte[] data)
        {
            var result = new SendCardResult()
            {
                Result = SendCardResultType.成功
            };
            Debug.WriteLine(string.Join(" ", data.Select(s => s.ToString("X2"))));
            var hex = data.ToHexString();
            if (hex.EndsWith("4B0115") || hex.EndsWith("4B0115656E64"))
            {
                result.Result = SendCardResultType.无卡或坏卡;
            }
            else if (hex.EndsWith("4B0116"))
            {
                result.Result = SendCardResultType.已加密卡;
            }
            else if ((data.Length == 7 && hex.EndsWith("656E64")) || hex == "656E64")
            {
                result.Result = SendCardResultType.指令结束;
            }
            else
            {
                if (hex.Length >= 22)
                {
                    //获取卡号
                    result.CardCode = hex.Substring(14, 8);
                }
                else
                {
                    result.CardCode = string.Empty;
                }

            }

            result.Order = hex;

            return result;
        }


        /// <summary>
        /// 加密卡片
        /// </summary>
        /// <param name="usbHid"></param>
        /// <returns></returns>
        public static SendCardResult SendJmjCard(this IUsbHid usbHid)
        {
            // 先加密扇区,再发卡
            //加密扇区
            Debug.WriteLine("加密扇区");
            var result = usbHid.SendCard("584B09504B0129");
            if (result.Result == SendCardResultType.成功)
            {
                Debug.WriteLine("发卡");
                //继续发卡
                result = usbHid.SendCard("584B09504B0105");
                Debug.WriteLine(result.Result.ToString() + " " + result.CardCode);
            }
            return result;
        }

        /// <summary>
        /// 发卡（所有卡)，总功能
        /// </summary>
        public static SendCardResult SendCard(this IUsbHid usbHid, string order, bool hasSector = true)
        {
            usbHid.ClearEvents();
            SendCardResult cardResult = new SendCardResult()
            {
                Result = SendCardResultType.等待结果
            };
            SendCardResult result = new SendCardResult
            {
                Result = SendCardResultType.等待结果
            };
            usbHid.OnReceiveMessaged += data =>
            {
                cardResult = GetSendCardResult(data);
                if (cardResult.Result != SendCardResultType.指令结束)
                {
                    result.Result = cardResult.Result;
                    result.Order = cardResult.Order;
                    result.CardCode = cardResult.CardCode;
                    result.Count = cardResult.Count;
                }
                else
                {
                    usbHid.ClearEvents();
                }
                result.OrderList.Add(cardResult.Order);
            };
            order = hasSector ? order + MyAppContext.Sector : order;
            usbHid.SendMessage(order);
            while (cardResult.Result != SendCardResultType.指令结束)
            {
                Thread.Sleep(100);
            }
            return result;
        }

        /// <summary>
        /// 锁板清除卡
        /// </summary>
        /// <param name="usbHid"></param>
        /// <param name="action"></param>
        public static void ClearBorder(this IUsbHid usbHid, Action<string> action)
        {
            usbHid.ClearEvents();
            usbHid.OnReceiveMessaged += data =>
            {
                var hex = data.ToHexString();
                var cardCode = hex.Substring(12, hex.Length - 12);
                action.Invoke(cardCode);
            };
            usbHid.SendMessage("584B1C5052010500000000000000000000000000000000A01500" + MyAppContext.Sector);
        }

        /// <summary>
        /// 加密机发测试卡（工程卡）
        /// </summary>
        public static void TestCard(this IUsbHid usbHid, Action<string> action)
        {
            usbHid.ClearEvents();
            usbHid.OnReceiveMessaged += data =>
            {
                var hex = data.ToHexString();
                var cardCode = hex.Substring(12, hex.Length - 12);
                action.Invoke(cardCode);
            };
            usbHid.SendMessage("584B1C5052010500000000000000000000000000000000A01300" + MyAppContext.Sector);
        }


        /// <summary>
        /// 加密机清除卡片
        /// </summary>
        public static SendCardResult ClearCard(this IUsbHid usbHid)
        {
            var result = usbHid.SendCard("584B09504B0128");
            return result;
        }

        /// <summary>
        /// 酒店开卡
        /// </summary>
        public static SendCardResult SendHotelCard(this IUsbHid usbHid,
            DateTime beginTime,
            DateTime endTime,
            int buildingNumber,
            int floorNumber,
            string roomNumber)
        {
            usbHid.ClearEvents();
            beginTime = DateTime.Today;
            endTime = DateTime.Today.AddDays(3);


            var bt = beginTime.ToString("yyMMddHHmm");
            var et = endTime.ToString("yyMMddHHmm");
            var bn = FormatStr(buildingNumber.ToString());
            var fn = FormatStr(floorNumber.ToString(), 4);
            var rm = FormatStr(roomNumber.ToString(), 4);
            var order = $"584B1E50520105{bt}{et}{bn}{fn}{rm}01B000010100";
            var result = usbHid.SendCard(order);
            return result;
        }
        private static string FormatStr(string str, int length = 2)
        {
            var len = str.Length;
            if (len > length)
            {
                str = str.Substring(1, length);
            }
            else
            {
                str = str.PadLeft(length, '0');
            }
            return str;
        }

        private static string GetTodayRange()
        {
            var time = DateTime.Now;
            var endTime = new DateTime(time.Year, time.Month, time.Day).AddDays(1);

            return DateTime.Now.ToString("yyMMddHHmm") + endTime.ToString("yyMMddHHmm");
        }

        /// <summary>
        /// 授权卡
        /// </summary>
        public static bool SendAuthorizeCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var code = $"585250520105{GetTodayRange()}000000000000B009";
            var result = usbHid.SendMessage(code, true);
            var resultHex = result.ToHexString();
            return resultHex.StartsWith("584B4B4B0105");
        }

        /// <summary>
        /// 经销商测试卡
        /// </summary>
        public static bool SendAgencyTestCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var result = usbHid.SendMessage("58525052010500000000000000000000000000000000A018", true);
            var resultHex = result.ToHexString();
            return resultHex.StartsWith("584B4B4B0105");
        }


        /// <summary>
        /// 时间卡
        /// </summary>
        public static bool SendTimeCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var code = $"585250520105{DateTime.Now.ToString("yyMMddHHmm")}0000000000000000000000B002";
            var result = usbHid.SendMessage(code, true);
            var resultHex = result.ToHexString();
            return resultHex.StartsWith("584B4B4B0105");
        }


        /// <summary>
        /// 退房
        /// </summary>
        public static SendCardResult ReturnRoom(this IUsbHid usbHid)
        {
            //usbHid.ClearEvents();
            //var code = $"584B0950520305";

            var result = usbHid.SendCard("584B0950520305");
            return result;
            //var result = usbHid.SendMessage(code, true);
            //var resultHex = result.ToHexString();
            //var resultCode = "58522B52520305";
            //if (resultCode.StartsWith(resultCode))
            //{
            //    var cardCode = resultHex.Substring(resultCode.Length, 6);
            //    return cardCode;
            //}
            //return null;
        }

        /// <summary>
        /// 记录卡
        /// </summary>
        public static bool SendRecordCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var code = $"585250520105{GetTodayRange()}000000000000B005";
            var result = usbHid.SendMessage(code, true);
            var resultHex = result.ToHexString();
            return resultHex.StartsWith("584B4B4B0105");
        }

        /// <summary>
        /// 酒店清除卡片信息
        /// </summary>
        public static bool ClearHotelCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var code = $"585250520111";
            var result = usbHid.SendMessage(code, true);
            var resultHex = result.ToHexString();
            return resultHex.StartsWith("585252520311");
        }

        /// <summary>
        /// 发工卡（测试卡)
        /// </summary>
        /// <param name="usbHid"></param>
        /// <returns></returns>
        public static SendCardResult SendFactoryTestCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var code = "584B07504B0108";
            var result = usbHid.SendCard(code, false);
            return result;
        }

        public static bool[] RedJmjCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();
            var results = new bool[16];
            var code = "584B08504B0330";
            for (int i = 0; i < results.Length; i++)
            {
                var orde = code + Convert.ToString(i + 1, 16).PadLeft(2,'0');
                var result = usbHid.SendCard(orde, false);
                results[i] = result.Result == SendCardResultType.成功;
            }
            return results;

        }

        /// <summary>
        /// 读卡片信息
        /// </summary>
        public static CardDetailInfo ReadCard(this IUsbHid usbHid)
        {
            usbHid.ClearEvents();

            var code = $"584B0950520310";
            var result = usbHid.SendCard(code);
            if (result.Result != SendCardResultType.成功)
            {
                return null;
            }

            var returnItem = new CardDetailInfo()
            {
                CardType = CardType.未知卡
            };
            var infos = result.OrderList.Skip(result.OrderList.Count - 3).Take(2);
            var resultHex = string.Join("", infos);
            var beginIndex = 14;
            var len = 8;
            returnItem.CardId = resultHex.Substring(beginIndex, len);
            if (resultHex.Replace(returnItem.CardId, "").Replace("0", "").Length == 0)
            {
                returnItem.CardType = CardType.新卡;
                return returnItem;
            }
            beginIndex += len;
            len = 10;
            var t = resultHex.Substring(beginIndex, len);
            returnItem.BeginTime = StrToDatetime(t);
            beginIndex += len;
            t = resultHex.Substring(beginIndex, len);
            returnItem.EndTime = StrToDatetime(t);

            beginIndex += len;
            len = 2;
            t = resultHex.Substring(beginIndex, len);
            returnItem.BuildingNumber = int.Parse(t);

            beginIndex += len;
            len = 4;
            t = resultHex.Substring(beginIndex, len);
            returnItem.FloorNumber = int.Parse(t);

            beginIndex += len;
            len = 4;
            returnItem.RoomNumber = resultHex.Substring(beginIndex, len);


            //内套房号
            beginIndex += len;
            len = 2;
            returnItem.InnerRoomNumber = resultHex.Substring(beginIndex, len);

            //客户用卡
            beginIndex += len;
            len = 2;
            t = resultHex.Substring(beginIndex, len);

            //卡类型
            beginIndex += len;
            len = 2;
            t = resultHex.Substring(beginIndex, len);

            if (int.TryParse(t, out int cardType))
            {
                returnItem.CardType = (CardType)cardType;
            }

            beginIndex += len;
            len = 2;
            t = resultHex.Substring(beginIndex, len);
            returnItem.CanOpenLocked = t == "01";

            beginIndex += len;
            len = 2;
            t = resultHex.Substring(beginIndex, len);
            returnItem.CanMulti = t == "01";

            return returnItem;

        }
        static DateTime? StrToDatetime(string str)
        {

            var year = int.Parse(str.Substring(0, 2));
            if (year == 0) return null;
            year += 2000;
            var month = int.Parse(str.Substring(2, 2));
            var day = int.Parse(str.Substring(4, 2));
            var hour = int.Parse(str.Substring(6, 2));
            var minute = int.Parse(str.Substring(8, 2));

            return new DateTime(year, month, day, hour, minute, 0);
        }
    }

    public class CardDetailInfo
    {
        /// <summary>
        /// 卡片类型
        /// </summary>
        public CardType CardType { get; set; }

        public string CardTypeString { get => CardType.ToString(); }

        /// <summary>
        /// 卡号
        /// </summary>
        public string CardId { get; set; }

        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime? BeginTime { get; set; }

        /// <summary>
        /// 结束时间
        /// </summary>
        public DateTime? EndTime { get; set; }

        /// <summary>
        /// 楼栋
        /// </summary>
        public int BuildingNumber { get; set; }

        /// <summary>
        /// 楼层
        /// </summary>
        public int FloorNumber { get; set; }

        /// <summary>
        /// 房间号
        /// </summary>
        public string RoomNumber { get; set; }

        /// <summary>
        /// 内套房号
        /// </summary>
        public string InnerRoomNumber { get; set; }

        /// <summary>
        /// 可开反锁
        /// </summary>
        public bool CanOpenLocked { get; set; }

        /// <summary>
        /// 可多卡开房
        /// </summary>
        public bool CanMulti { get; set; }
    }

    /// <summary>
    /// 卡片类型
    /// </summary>

    public enum CardType
    {
        未知卡 = 1000,
        新卡 = 2000,
        客人卡 = 0,
        时间卡 = 2,
        组控卡 = 3,
        应急卡常开卡 = 4,
        记录卡 = 5,
        挂失卡 = 6,
        授权卡 = 9,
        总控卡 = 10,
        楼栋卡 = 11,
        楼层卡 = 12,
        测试卡 = 13,
        清除卡 = 15,
        组控设置卡 = 16,
        保洁卡 = 17,
        经销商测试卡 = 18,
        门禁设置卡 = 19,
        取电卡 = 20,
        指纹录入卡 = 21,
        指纹清除卡 = 22,
        信息卡 = 99


    }

}
